package io.dy.template;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.alibaba.excel.write.metadata.fill.FillWrapper;
import io.dy.handler.MergeHandler;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.Data;
import java.io.*;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;

/**
 * @author : dmj
 * @date: 2024/7/11 3:43 下午
 * @description: excel导出、pdf导出 模版方法
 */
public abstract class ExcelAndPdfExportTemplate {

    private final static String SEPARATOR = "/";

    /**
     * 导出类型 注意 导出pdf时 需要手动给属性 settleExcelToPDF 赋值
     * @see ExportType
     * @return
     */
    public abstract ExportType exportType();

    /**
     * 模版路径
     */
    public abstract String templateUrl();

    /**
     * 导出需要的数据 对象、集合、导出的文件名
     */
    public abstract <T>  ExportData exportData(T req);

    /**
     * excel填充样式 可继承自定义 (切勿直接修改此地)
     */
    public FillConfig fillConfig(){
        return FillConfig.builder()
                .forceNewRow(Boolean.TRUE).autoStyle(true).build();
    }

    /**
     * 导出的主体方法
     */
    public <T> void export(HttpServletResponse response, HttpServletRequest httpServletRequest, T req){
        ExportData exportData = this.exportData(req);
        if(Objects.isNull(exportData)){throw new RuntimeException("数据查询异常，导出失败");}
        //1、获取对象信息
        Object exportObj = exportData.getObj();

        //2、获取集合对象
        Map<String, Collection<?>> collectionMap = exportData.getCollectionMap();
        if(Objects.isNull(exportObj) && CollectionUtil.isEmpty(collectionMap)){
            throw new RuntimeException("数据查询异常，导出失败");
        }

        //3、获取导出文件名
        String exportFileName = Optional.ofNullable(exportData.getExportFileName()).orElse("导出文件");

        Path tempExcelDir = null;
        Path tempPdfDir = null;
        try{
            //4、获取模版信息
            InputStream templateStream = this.getClass().getResourceAsStream(this.templateUrl());

            //5、获取EasyExcel
            String userAgent = httpServletRequest.getHeader("User-Agent");
            String formFileName = exportFileName;
            if (userAgent.contains("MSIE") || userAgent.contains("Trident")) {
                formFileName = URLEncoder.encode(formFileName, "UTF-8");
            } else {
                // 非IE浏览器的处理：
                formFileName = URLEncoder.encode(formFileName, "utf-8");
            }
            response.setHeader("Content-disposition", String.format("attachment; filename=%s", formFileName));
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setCharacterEncoding("UTF-8");

            //6、判断导出的是excel还是pdf
            if(ExportType.EXCEL.name().equals(this.exportType().name())){
                write(response.getOutputStream(), templateStream, exportObj, collectionMap);
            }else if(ExportType.PDF.name().equals(this.exportType().name())){
                //todo
            }
        }catch (Exception e){
            throw new RuntimeException("导出pdf失败");
        }finally {
            try{
                if (null != tempExcelDir) {
                    Files.delete(tempExcelDir);
                }
                if (null != tempPdfDir) {
                    Files.delete(tempPdfDir);
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    private void write(OutputStream outputStream, InputStream templateStream, Object object, Map<String, Collection<?>> collectionMap){
        ExcelWriter excelWriter = EasyExcel.write(outputStream).withTemplate(templateStream).build();
        WriteSheet writeSheet = EasyExcel.writerSheet().registerWriteHandler(new MergeHandler()).build();
        //WriteSheet writeSheet = EasyExcel.writerSheet().build();
        FillConfig fillConfig = this.fillConfig();

        if(Objects.nonNull(object)){
            excelWriter.fill(object, fillConfig, writeSheet);
        }
        if(CollectionUtil.isNotEmpty(collectionMap)){
            collectionMap.forEach((key,collection)-> {
                excelWriter.fill(new FillWrapper(key, collection), fillConfig, writeSheet);
            });
        }
        excelWriter.finish();
    }

    public enum ExportType{PDF,EXCEL;}

    @Data
    public
    class ExportData{
        private Object obj;
        private Map<String, Collection<?>> collectionMap;
        private String exportFileName;
    }
}
